每個React網頁 都是由基礎價夠堆疊出來,對於使用者,只能看到結果
所以按照元件一層層嵌套下去,當然沒問題。但是如果最底層的按鈕要返回 他已經登出這件事情怎麼辦呢?
npm 安裝
npm i react-router-dom
一樣是從app.js開始,但不一樣的事要從app.js的外面著手
app.js移動 至 新資料夾:page =>重新命名為app.jsx
引用自創的全域框架 ContextProvider.jsx
從專案 > src > index.js 開始
/*file index.js*/
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.scss';//global css
import App from './page/App';/*app.js移動 至 新資料夾:page =>重新命名為app.jsx*/
import { ContextProvider } from './constant/ContextProvider';
import { BrowserRouter, Route, Routes } from "react-router-dom";
/*Route寫法可能因為版本 引用元件會完全不一樣 但是架構類似*/
ReactDOM.render(
<React.StrictMode>
<ContextProvider>
<BrowserRouter>
<Routes>
<Route path='/' element={<App />} />
</Routes>
</BrowserRouter>
</ContextProvider>
</React.StrictMode>,
document.getElementById('root')
);
src > 新增資料夾:constant > 新增檔案:ContextProvider.jsx
/*file ContextProvider.jsx*/
import { createContext, useContext, useState } from "react";
import { redirect } from "react-router-dom";/*這裡轉址 也因為版本import元件不一樣寫法差不多*/
const StateContext = createContext({
user: null,
token: null,
notification: null,
setUser: () => { },
setToken: () => { },
setNotification: () => { },
setLoading: () => { }
});
export const ContextProvider = ({ children }) => {
const [user, _setUser] = useState(localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')) : {});
const [token, _setToken] = useState(localStorage.getItem('ACCESS_TOKEN'));
const [notification, _setNotification] = useState('');
const [isLoading, _setLoading] = useState(true);
const setUser = (user) => {
if (user && typeof user === 'object' && user['id']) {
_setUser(user);
localStorage.setItem('user', JSON.stringify(user));
} else if (user === 'logout') {
_setUser(null);
localStorage.removeItem('user');
setToken(null);
return redirect('/')
} else {
_setUser(null);
localStorage.removeItem('user');
setToken(null);
return redirect('/login', {
onFinish: () => setNotification('登入逾期失效')
})
}
}
const setToken = (token) => {
if (token) {
_setToken(token);
localStorage.setItem('ACCESS_TOKEN', token);
} else {
_setToken(null);
localStorage.removeItem('ACCESS_TOKEN');
}
}
const setNotification = (message) => {
_setNotification(message);
setTimeout(() => {
_setNotification('');
}, 5000)
}
const setLoading = (isLoading) => {
if (isLoading) {
_setLoading(true);
} else {
_setLoading(false);
}
}
return (
<StateContext.Provider value={{
user,
setUser,
token,
setToken,
notification,
setNotification,
setLoading
}}>
{isLoading &&
<div id="loading" className="d-flex justify-content-center align-items-center">
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
}
{notification && <div className="alert alert-box alert-success">{notification}</div>}
{children}
</StateContext.Provider>
)
}
export const userStateContext = () => useContext(StateContext)
補充css外觀
$theme-colors: ( 'primary':#407855 );
@import '~bootstrap/scss/bootstrap';
#loading {
position: absolute;
top: 0;
left: 0;
min-width: 100vw;
min-height: 100vh;
background-color: rgba(111,111,111,0.35);
z-index: 2090;
cursor: progress;
}
到這裡基本上可以看到 綠色(#4407855)的按鈕跟loading了
/*file app.jsx*/
import React, { useEffect } from 'react';
import { userStateContext } from "../constant/ContextProvider";
import 'sweetalert2/src/sweetalert2.scss'
import { useNavigate } from "react-router-dom";
function App() {
const { user, setUser, token, setToken, setLoading, setNotification } = userStateContext();/*引用全域函數*/
const navigate = useNavigate();
useEffect(() => {/*初始化*/
setLoading(false);
}, []);/*這個矩陣是很重要的*/
function fakeLogin() {
setLoading(true);
setToken('kasnvlawejnflasdfjklfsadnf');
setUser({ id: '新用戶', email: "dsafsa@afs.com" });
setNotification('登入成功');
navigate("about", {
onFinish: () => setLoading(false)
});
}
return (
<div className="App">
{user && Object.keys(user).length && user['id'] ? "歡迎" + user['id'] : null}
<button className="btn btn-primary" onClick={fakeLogin} >登入</button>
</div>
);
}
export default App;
/*file: index.js*/
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.scss';//gloable css
import App from './page/App';
import About from './page/About';/* 引入新頁面*/
import { ContextProvider } from './constant/ContextProvider';
import { BrowserRouter, Route, Routes } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<ContextProvider>
<BrowserRouter>
<Routes>
<Route path='/' element={<App />} />
<Route path='about' element={<About />} />/* 給予路由 yourDomain/about*/
</Routes>
</BrowserRouter>
</ContextProvider>
</React.StrictMode>,
document.getElementById('root')
);
新增檔案 src > page > About.jsx
/*file: About.jsx*/
import React, { useEffect } from 'react';
import { userStateContext } from "../constant/ContextProvider";
function About() {
const { user } = userStateContext();/*引用全域函數*/
return (
<div className="App">
{user && Object.keys(user).length && user['id'] ? "歡迎" + user['id'] : null} 登入
</div>
);
}
export default About;
到這邊基本上就可以達成
react其實有點小小缺點,資料只能下向傳承,所以要跨區塊傳遞,會有點小麻煩。
我寫了javascript兩年,沒人教的情況下,有些好用的方法真的會不知道,知道都是抄來的
以前沒有人可以問,現在有ChatGPT可以問。我的文章不斷要求不使用ChatGPT。
用在ChatGPT一出來,就開始用。用了非常多,而且都是連續問很多問題。(沒辦法上傳gif檔)
我在這裡可以很肯定地說,如果你是要最上面金字塔圖 相鄰兩區塊的問題 已經是複雜度的極限。
ChatGPT對於橫向問題處理很好,但對於1.多系統 2.縱深架構,他會提出的答案,效果可能不夠好。
技術參考來源: 全域資料傳遞:https://www.youtube.com/watch?v=qJq9ZMB2Was&ab_channel=TheCodeholic